package org.swxjava.assembler.avm1;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.swxjava.util.Log;
import org.swxjava.util.LogFactory;

import org.swxjava.assembler.Constants;
import org.swxjava.assembler.ObjectCompiler;

public class AsObject implements ObjectCompiler {

	/** Logger */
	private static final Log LOG = LogFactory.getLog(AsObject.class);

	/** Object internal map */
	private List<AsObjectProperty> props;
	private AsObjectProperty lastProp = null;
	
	public AsObject() {
		props = new ArrayList<AsObjectProperty>();
	}
	
	public int getByteSize() {
		if(props == null || props.size() == 0) {
			return 5; // INT int(4) = Object size
		} else {
			return props.get(0).getByteSize();
		}
	}

	public boolean add(AsObjectProperty prop) {
		if(lastProp != null) {
			lastProp.setNext(prop);
		}
		lastProp = prop;
		return props.add(prop);
	}
	
	public byte[] toBytecode() {
		// TODO Auto-generated method stub
		return null;
	}

	public String toString() {
		StringBuffer bytecode = new StringBuffer();
		
		// First push
		if(!props.isEmpty()) {
			bytecode.append(Constants.ACTION_PUSH);
			ObjectCompiler firstByteLength = new AsByteLength(getByteSize());
			bytecode.append(firstByteLength.toString());
			if(LOG.isDebugEnabled()) {
				LOG.debug("Object : " + Constants.ACTION_PUSH + " " + firstByteLength.toString());
			}
		}

		AsObjectProperty lastProp = null;
		for (Iterator<AsObjectProperty> it = props.iterator(); it.hasNext();) {
			AsObjectProperty prop = it.next();

			// Need to PUSH
			if (lastProp != null && (lastProp.isComplex() || lastProp.isNew())) {
				LOG.debug("(at end) IS COMPLEX - " + lastProp.value().getClass().getName());
				// PUSH BYTESIZE
				bytecode.append(Constants.ACTION_PUSH);
				ObjectCompiler size = new AsByteLength(prop.getByteSize());
				bytecode.append(size.toString());
				if(LOG.isDebugEnabled()) {
					LOG.debug(" - push : " + Constants.ACTION_PUSH + " " + size.toString());
				}
			}
			// NAME VALUE NAME VALUE ....
			String name = prop.name().toString();
			if(LOG.isDebugEnabled()) {
				LOG.debug(" - name  : " + name);
			}
			String value = prop.value().toString();
			if(LOG.isDebugEnabled()) {
				LOG.debug(" - value : " + value);
			}
			bytecode.append(name).append(value);
			lastProp = prop;
		}

		// Store number of properties.
		ObjectCompiler objectSize = new AsInt(props.size());

		// Need to PUSH
		if (lastProp != null && (lastProp.isComplex() || lastProp.isNew())) {
			LOG.debug("(at end) IS COMPLEX - " + lastProp.value().getClass().getName());
			// PUSH BYTESIZE
			bytecode.append(Constants.ACTION_PUSH);
			ObjectCompiler propLengthBytesize = new AsByteLength(objectSize.getByteSize());
			bytecode.append(propLengthBytesize.toString());
			if(LOG.isDebugEnabled()) {
				LOG.debug(" - push : " + Constants.ACTION_PUSH + " " + propLengthBytesize.toString());
			}
		}
		bytecode.append(objectSize.toString());
		if(LOG.isDebugEnabled()) {
			LOG.debug(" - length : " + objectSize.toString());
		}

		// ACTION_INIT_OBJECT
		bytecode.append(Constants.ACTION_INIT_OBJECT);
		if(LOG.isDebugEnabled()) {
			LOG.debug(" - initObject : " + Constants.ACTION_INIT_OBJECT);
		}

		return bytecode.toString();
	}
}
